package cn.iocoder.yudao.module.member.service.userpromotionrecords;

import cn.iocoder.yudao.module.member.controller.admin.userpointrecords.vo.UserPointRecordsSaveReqVO;
import cn.iocoder.yudao.module.member.controller.app.userpromotionrecords.vo.AppUserPromotionRecordsGroupRespVO;
import cn.iocoder.yudao.module.member.controller.app.userpromotionrecords.vo.AppUserPromotionRecordsPageReqVO;
import cn.iocoder.yudao.module.member.controller.app.userpromotionrecords.vo.AppUserPromotionRecordsStatisticsRespVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.userpointrecords.UserPointRecordsBizTypeEnum;
import cn.iocoder.yudao.module.member.enums.userpointrecords.UserPointRecordsOpTypeEnum;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.member.service.usercommission.UserCommissionService;
import cn.iocoder.yudao.module.member.service.userpointrecords.UserPointRecordsService;
import cn.iocoder.yudao.module.member.service.userwithdraw.UserWithdrawService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.member.controller.admin.userpromotionrecords.vo.*;
import cn.iocoder.yudao.module.member.dal.dataobject.userpromotionrecords.UserPromotionRecordsDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.member.dal.mysql.userpromotionrecords.UserPromotionRecordsMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * 用户推广记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class UserPromotionRecordsServiceImpl implements UserPromotionRecordsService {

    @Value(value = "${zhima.invite.points}")
    private Integer invitePoints;

    @Resource
    private MemberUserService memberUserService;
    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private UserPointRecordsService userPointRecordsService;
    @Resource
    private UserPromotionRecordsMapper userPromotionRecordsMapper;
    @Resource
    private ApplicationContext applicationContext;

    private UserCommissionService getUserCommissionService() {
        return applicationContext.getBean(UserCommissionService.class);
    }

    private UserWithdrawService getUserWithdrawService() {
        return applicationContext.getBean(UserWithdrawService.class);
    }

    @Override
    public Long createUserPromotionRecords(UserPromotionRecordsSaveReqVO createReqVO) {
        // 插入
        UserPromotionRecordsDO userPromotionRecords = BeanUtils.toBean(createReqVO, UserPromotionRecordsDO.class);
        userPromotionRecordsMapper.insert(userPromotionRecords);
        // 返回
        return userPromotionRecords.getId();
    }

    @Override
    public List<Long> getInviteeUserIds(Long inviterUserId) {
        List<UserPromotionRecordsDO> userPromotionRecordsDOList = userPromotionRecordsMapper.selectByInviterUserId(inviterUserId);
        if (CollectionUtils.isEmpty(userPromotionRecordsDOList)) {
            return new ArrayList<>();
        }
        return userPromotionRecordsDOList.stream()
                .map(userPromotionRecordsDO -> userPromotionRecordsDO.getInviteeUserId())
                .collect(Collectors.toList());
    }

    private void addUserPointsRecords(Long userId, Long bizId, Integer points) {
        UserPointRecordsSaveReqVO userPointRecordsSaveReqVO = new UserPointRecordsSaveReqVO();
        userPointRecordsSaveReqVO.setUserId(userId);
        userPointRecordsSaveReqVO.setOpType(UserPointRecordsOpTypeEnum.ADD.getCode());
        userPointRecordsSaveReqVO.setBizType(UserPointRecordsBizTypeEnum.INVITE.getType());
        userPointRecordsSaveReqVO.setBizId(bizId);
        userPointRecordsSaveReqVO.setPoints(points);
        userPointRecordsSaveReqVO.setTotalPoints(memberUserService.getUser(userId).getPoints());
        userPointRecordsSaveReqVO.setCreator(userId.toString());
        userPointRecordsService.createUserPointRecords(userPointRecordsSaveReqVO);
    }

    @Override
    public Long createUserPromotionRecords(Long inviteeUserId, String inviteCode) {
        if (StringUtils.isEmpty(inviteCode)) {
            throw exception(USER_INVITE_CODE_EMPTY);
        }
        UserPromotionRecordsDO userPromotionRecordsDO = userPromotionRecordsMapper.selectByInviteeUserId(inviteeUserId);
        if (Objects.nonNull(userPromotionRecordsDO)) {
            throw exception(USER_PROMOTION_RECORDS_EXISTS);
        }
        MemberUserDO memberUserDOInvitee = memberUserService.validateUserExists(inviteeUserId);
        if (Objects.isNull(memberUserDOInvitee)) {
            throw exception(USER_NOT_EXISTS);
        }
        MemberUserDO memberUserDOInviter = memberUserMapper.selectByInviteCode(inviteCode);
        if (Objects.isNull(memberUserDOInviter)) {
            throw exception(USER_INVITE_CODE_NOT_EXISTS);
        }
        if (memberUserDOInviter.getId().equals(inviteeUserId)) {
            throw exception(USER_PROMOTION_RECORDS_CAN_NOT_SELF_INVITE);
        }

        userPromotionRecordsDO = new UserPromotionRecordsDO();
        Long inviterUserId = memberUserDOInviter.getId();
        userPromotionRecordsDO.setInviterUserId(inviterUserId);
        userPromotionRecordsDO.setInviteeUserId(inviteeUserId);
        userPromotionRecordsDO.setCreator(inviteeUserId.toString());
        userPromotionRecordsDO.setCreateTime(LocalDateTime.now());
        userPromotionRecordsDO.setUpdater(inviteeUserId.toString());
        userPromotionRecordsDO.setUpdateTime(LocalDateTime.now());

        userPromotionRecordsMapper.insert(userPromotionRecordsDO);

        memberUserService.updateUserPoints(inviterUserId, invitePoints);
        addUserPointsRecords(inviterUserId, inviteeUserId, invitePoints);

        memberUserService.updateUserPoints(inviteeUserId, invitePoints);
        addUserPointsRecords(inviteeUserId, inviterUserId, invitePoints);

        return userPromotionRecordsDO.getId();
    }

    @Override
    public void updateUserPromotionRecords(UserPromotionRecordsSaveReqVO updateReqVO) {
        // 校验存在
        validateUserPromotionRecordsExists(updateReqVO.getId());
        // 更新
        UserPromotionRecordsDO updateObj = BeanUtils.toBean(updateReqVO, UserPromotionRecordsDO.class);
        userPromotionRecordsMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserPromotionRecords(Long id) {
        // 校验存在
        validateUserPromotionRecordsExists(id);
        // 删除
        userPromotionRecordsMapper.deleteById(id);
    }

    private void validateUserPromotionRecordsExists(Long id) {
        if (userPromotionRecordsMapper.selectById(id) == null) {
            throw exception(USER_PROMOTION_RECORDS_NOT_EXISTS);
        }
    }

    @Override
    public UserPromotionRecordsDO getUserPromotionRecords(Long id) {
        return userPromotionRecordsMapper.selectById(id);
    }

    @Override
    public PageResult<UserPromotionRecordsRespVO> getUserPromotionRecordsPage(UserPromotionRecordsPageReqVO pageReqVO) {
        if (Objects.nonNull(pageReqVO.getUserId())) {
            pageReqVO.setInviterUserId(pageReqVO.getUserId());
        } else if (StringUtils.hasLength(pageReqVO.getMobile())) {
            pageReqVO.setInviterUserId(0L);
            MemberUserDO memberUserDO = memberUserService.getUserByMobile(pageReqVO.getMobile());
            if (Objects.nonNull(memberUserDO)) {
                pageReqVO.setInviterUserId(memberUserDO.getId());
            }
        } else if (StringUtils.hasLength(pageReqVO.getInviteCode())) {
            pageReqVO.setInviterUserId(0L);
            MemberUserDO memberUserDO = memberUserService.getUserByInviteCode(pageReqVO.getInviteCode());
            if (Objects.nonNull(memberUserDO)) {
                pageReqVO.setInviterUserId(memberUserDO.getId());
            }
        }
        PageResult<UserPromotionRecordsDO> pageResult = userPromotionRecordsMapper.selectPage(pageReqVO);
        UserCommissionService userCommissionService = getUserCommissionService();
        PageResult<UserPromotionRecordsRespVO> userPromotionRecordsRespVOPageResult = BeanUtils.toBean(pageResult, UserPromotionRecordsRespVO.class);
        List<UserPromotionRecordsRespVO> userPromotionRecordsRespVOList = userPromotionRecordsRespVOPageResult.getList();
        for (UserPromotionRecordsRespVO userPromotionRecordsRespVO : userPromotionRecordsRespVOList) {
            Long inviterUserId = userPromotionRecordsRespVO.getInviterUserId();
            MemberUserDO memberUserDOInviter = memberUserService.getUser(inviterUserId);
            if (Objects.nonNull(memberUserDOInviter)) {
                userPromotionRecordsRespVO.setInviterNickname(memberUserDOInviter.getNickname());
                userPromotionRecordsRespVO.setInviterInviteCode(memberUserDOInviter.getInviteCode());
            }
            Long inviteeUserId = userPromotionRecordsRespVO.getInviteeUserId();
            MemberUserDO memberUserDOInvitee = memberUserService.getUser(inviteeUserId);
            if (Objects.nonNull(memberUserDOInvitee)) {
                userPromotionRecordsRespVO.setInviteeNickname(memberUserDOInvitee.getNickname());
                userPromotionRecordsRespVO.setInviteeInviteCode(memberUserDOInvitee.getInviteCode());
                userPromotionRecordsRespVO.setInviteeRegTime(memberUserDOInvitee.getCreateTime());
            }
            Integer firstInviteRecharge = userCommissionService.firstTotalRecharge(inviteeUserId);
            userPromotionRecordsRespVO.setRechargeStatus(firstInviteRecharge > 0);
            userPromotionRecordsRespVO.setCumulativeRecharge(firstInviteRecharge);
            userPromotionRecordsRespVO.setInvitedRecharge(userCommissionService.secondTotalRecharge(inviteeUserId));
        }
        userPromotionRecordsRespVOPageResult.setList(userPromotionRecordsRespVOList);
        return userPromotionRecordsRespVOPageResult;
    }

    @Override
    public PageResult<UserPromotionRecordsRespVO> getUserPromotionRecordsPageForApp(AppUserPromotionRecordsPageReqVO pageReqVOApp) {
//        UserCommissionService userCommissionService = getUserCommissionService();
        UserPromotionRecordsPageReqVO pageReqVO = new UserPromotionRecordsPageReqVO();
        BeanUtils.copyProperties(pageReqVOApp, pageReqVO);
        return getUserPromotionRecordsPage(pageReqVO);
//        PageResult<UserPromotionRecordsDO> pageResult = getUserPromotionRecordsPage(pageReqVO);
//        PageResult<UserPromotionRecordsRespVO> userPromotionRecordsRespVOPageResult = BeanUtils.toBean(pageResult, UserPromotionRecordsRespVO.class);
//        List<UserPromotionRecordsRespVO> userPromotionRecordsRespVOList = userPromotionRecordsRespVOPageResult.getList();
//        for (UserPromotionRecordsRespVO userPromotionRecordsRespVO : userPromotionRecordsRespVOList) {
//            Long inviteeUserId = userPromotionRecordsRespVO.getInviteeUserId();
//            Integer firstInviteRecharge = userCommissionService.firstTotalRecharge(inviteeUserId);
//            userPromotionRecordsRespVO.setRechargeStatus(firstInviteRecharge > 0);
//            userPromotionRecordsRespVO.setCumulativeRecharge(firstInviteRecharge);
//            userPromotionRecordsRespVO.setInvitedRecharge(userCommissionService.secondTotalRecharge(inviteeUserId));
//        }
//        userPromotionRecordsRespVOPageResult.setList(userPromotionRecordsRespVOList);
//        return userPromotionRecordsRespVOPageResult;
    }

    @Override
    public AppUserPromotionRecordsStatisticsRespVO getUserPromotionRecordsStatistics(Long userId) {
        AppUserPromotionRecordsStatisticsRespVO appUserPromotionRecordsStatisticsRespVO = new AppUserPromotionRecordsStatisticsRespVO();
        AppUserPromotionRecordsGroupRespVO appUserPromotionRecordsGroupRespVO = userPromotionRecordsMapper.groupByInviterUserId(userId);
        appUserPromotionRecordsStatisticsRespVO.setPromotionUserCount(Objects.isNull(appUserPromotionRecordsGroupRespVO) ? 0 :
                appUserPromotionRecordsGroupRespVO.getPromotionUserCount());
        UserCommissionService userCommissionService = getUserCommissionService();
        Integer totalCommission = userCommissionService.totalCommissionByUserId(userId);
        appUserPromotionRecordsStatisticsRespVO.setTotalCommission(totalCommission);
        UserWithdrawService userWithdrawService = getUserWithdrawService();
        Integer totalWithdraw = userWithdrawService.totalWithdrawByUserId(userId);
        appUserPromotionRecordsStatisticsRespVO.setWithdrawAvailable(userWithdrawService.withdrawAvailable(totalCommission - totalWithdraw));
        return appUserPromotionRecordsStatisticsRespVO;
    }

    @Override
    public List<UserPromotionRecordsDO> getByInviterUserId(Long inviterUserId) {
        return userPromotionRecordsMapper.selectByInviterUserId(inviterUserId);
    }

    @Override
    public UserPromotionRecordsDO getByInviteeUserId(Long inviteeUserId) {
        return userPromotionRecordsMapper.selectByInviteeUserId(inviteeUserId);
    }

}